import { Directive, ElementRef, Input, Output, EventEmitter, HostListener } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { saveAs } from 'file-saver';

import { HttpServer } from '@core/net/http-server';

@Directive({
  selector: '[download-file]'
})
export class DownloadFileDirective {

  /**
   * 请求参数
   */
  @Input('http-data') httpData: any;

  /**
   * 请求类型
   */
  @Input('http-method') httpMethod: 'get' | 'post' = 'get';

  /**
   * 下载地址
   */
  @Input('http-url') httpUrl: string;

  /**
   * 指定文件名，若为空从服务端返回的 `header` 中获取 `filename`、`x-filename`
   */
  @Input('file-name') fileName: string;

  /**
   * 成功回调
   */
  @Output() success: EventEmitter<any> = new EventEmitter<any>();

  /**
   * 错误回调
   */
  @Output() error: EventEmitter<any> = new EventEmitter<any>();

  constructor(
    private el: ElementRef,
    private http: HttpServer
  ) { }

  private getDisposition(data: string) {
    const arr: any = (data || '')
      .split(';')
      .filter(i => i.includes('='))
      .map(v => {
        const strArr = v.split('=');
        const utfId = `UTF-8''`;
        let value = strArr[1];
        if (value.startsWith(utfId)) {
          value = value.substr(utfId.length);
        }
        return { [strArr[0].trim()]: value };
      });
    return arr.reduce((o, item: any) => item, {});
  }

  @HostListener('click')
  _click() {
    this.el.nativeElement.disabled = true;
    this.http.requestStream(this.httpMethod, this.httpUrl, this.httpData)
      .subscribe((res: HttpResponse<Blob>) => {
        if (res.status !== 200 || res.body.size <= 0) {
          this.error.emit(res);
          return;
        }
        const disposition: any = this.getDisposition(
          res.headers.get('content-disposition')
        );
        const fileName =
          this.fileName ||
          disposition[`filename*`] ||
          disposition[`filename`] ||
          res.headers.get('filename') ||
          res.headers.get('x-filename');
        saveAs(res.body, decodeURI(fileName));
        this.success.emit(res);
        this.el.nativeElement.disabled = false;
      }, err => {
        this.error.emit(err);
        this.el.nativeElement.disabled = false;
      });
  }

}
